/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package model;

import Aleatorio.Distribuciones.GeneradorAleatorio;
import Aleatorio.Distribuciones.GeneradorExponencial;
import Aleatorio.Distribuciones.GeneradorUniforme;
import java.util.ArrayList;
import java.util.TreeSet;

/**
 *
 * @author Driv
 */
public class Controller {
    private int tiempoSimulacion;
    private float precioUnAviso;
    private float precioDosAvisos;
    private float costoError;
    private GeneradorAleatorio generadorLlegada;
    private GeneradorAleatorio generadorCantidadDeAvisos;
    private GeneradorAleatorio generadorError;
    private GeneradorAleatorio generadorTiempoAtencion;
    private TreeSet<Evento> listaEventos;
    private ArrayList<DatosFila> listaFilas;
    private boolean servidor1Libre;
    private boolean servidor2Libre;
    private int colaClientes;
    private double tiempoActual;
    private double randomTiempoAviso;
    private double TiempoAviso;
    private double tiempoFinAviso;
    private double randomCantidadDeAvisos;
    private double tiempoEntreLlegadas;
    private double tiempoLlegada;
    private double randomEntreLlegadas;
    private double randomError2;
    private double randomError1;
    private boolean error1;
    private boolean error2;
    private float acumGanancias;
    private double tiempoInicio;
    private int cantidadAvisos;
    private float ganancia;
    private float perdida;
    private String nombreEvento;







    public void set(int tiempoSimulacion, int semillaLegada, int semillaTiempoAtencion, int semillaCantidad, int semillaError, float precioUnAviso, float precioDosAvisos, float costoError){
        listaEventos = new TreeSet<Evento>();
        listaFilas = new ArrayList<DatosFila>();
        generadorLlegada = new GeneradorExponencial(semillaLegada,10);
        generadorTiempoAtencion = new GeneradorUniforme(semillaTiempoAtencion, 3, 7);
        generadorCantidadDeAvisos = new GeneradorUniforme(semillaCantidad);
        generadorError = new GeneradorUniforme(semillaError);
        this.tiempoSimulacion = tiempoSimulacion;
        this.precioUnAviso = precioUnAviso;
        this.precioDosAvisos = precioDosAvisos;
        this.costoError = costoError;
        servidor1Libre = true;
        servidor2Libre = true;

        //Vector estado;
        tiempoActual = 0;
        colaClientes = 0;
        tiempoInicio = 0;

    }

    protected void addEvento(Evento e){
        listaEventos.add(e);
    }

    protected void ejecutarEvento(){
        listaEventos.first().ejecutar(this);
    }

    public void ejecutarSimulacion(){
        nuevoEventoLlegadaCliente();
        Evento eventoActual;
        while(tiempoActual < tiempoSimulacion){
            eventoActual = listaEventos.first();
            tiempoActual = eventoActual.getTiempo();
            listaEventos.remove(eventoActual);
            eventoActual.ejecutar(this);
            nombreEvento = eventoActual.getNombre();
            listaFilas.add(armarFila());
            limpiarCampos();
        }
    }

    void liberarReceptor() {
        if(!servidor1Libre && !servidor2Libre){ servidor1Libre = true;
        return;
        }
        if(!servidor1Libre) servidor1Libre = true;
        else servidor2Libre = true;
    }

    private DatosFila armarFila(){
        if (nombreEvento.compareTo("Llegada Cliente")== 0)
            return new DatosFila(nombreEvento, tiempoActual, randomEntreLlegadas, tiempoEntreLlegadas, tiempoActual+tiempoEntreLlegadas,
                colaClientes, randomCantidadDeAvisos, cantidadAvisos, randomTiempoAviso, TiempoAviso,
                TiempoAviso + tiempoActual, receptoresLibres(), randomError1,
                error1 + "", randomError2, error2 + "", perdida, ganancia, acumGanancias);
        else
            return new DatosFila(nombreEvento, tiempoActual, randomEntreLlegadas, tiempoEntreLlegadas, 0,
                colaClientes, randomCantidadDeAvisos, cantidadAvisos, randomTiempoAviso, TiempoAviso,
                0, receptoresLibres(), randomError1,
                error1 + "", randomError2, error2 + "", perdida, ganancia, acumGanancias);
    }

    public boolean servidoresLibres(){
        return servidor1Libre || servidor2Libre;
    }

    public boolean atenderCliente(){
        if (servidor1Libre && colaClientes > 0){
            servidor1Libre = false;
            colaClientes--;
            nuevoEventoFinAtencionCliente();
            return true;
        }
        if (servidor2Libre && colaClientes > 0){
            servidor2Libre = false;
            colaClientes--;
            nuevoEventoFinAtencionCliente();
            return true;
        }
        return false;
    }

    public void agregarCliente(){
        colaClientes++;
    }

    public void agregarEvento(Evento e){
        listaEventos.add(e);
    }

    public double getTiempoProximaLlegada(){
        return generadorLlegada.siguiente();
    }

    public double getTiempoAtencion(){
        return generadorTiempoAtencion.siguiente();
    }

    public double getTiempoActual(){
        return tiempoActual;
    }

    public void nuevoEventoFinAtencionCliente(){
        TiempoAviso = generadorTiempoAtencion.siguiente();
        randomTiempoAviso = generadorTiempoAtencion.ultimoRandom();
        if ((randomCantidadDeAvisos = generadorCantidadDeAvisos.siguiente()) < 0.5){
            cantidadAvisos = 2;
        }
        else cantidadAvisos = 1;
        listaEventos.add(new EventoFinAtencionCliente(TiempoAviso+tiempoActual,cantidadAvisos == 2));
    }

    public void nuevoEventoLlegadaCliente(){
        tiempoEntreLlegadas = generadorLlegada.siguiente();
        randomEntreLlegadas = generadorLlegada.ultimoRandom();
        listaEventos.add(new EventoLlegadaCliente(tiempoActual + tiempoEntreLlegadas));
    }

    public void registrarFinAviso1(){
        randomError1 = generadorError.siguiente();
        if (randomError1 < 0.02){
            error1 = true;
            perdida = costoError;
            acumGanancias -= costoError;
        }
        acumGanancias += ganancia = precioUnAviso;
    }

    public void registrarFinAviso2(){
        randomError2 = generadorError.siguiente();
        if (randomError2 < 0.02){
            error2 = true;
            acumGanancias -= perdida = costoError;
        }
        ganancia = precioDosAvisos;
        acumGanancias +=  -precioUnAviso + precioDosAvisos;
    }

    private void limpiarCampos() {
      randomTiempoAviso = 0;
      TiempoAviso = 0;
      randomCantidadDeAvisos = 0;
      tiempoEntreLlegadas = 0;
      randomEntreLlegadas = 0;
      randomError2 = 0;
      randomError1 = 0;
      cantidadAvisos = 0;
      ganancia = 0;
      perdida= 0;
      error1 = false;
      error2 = false;
    }

    private int receptoresLibres(){
        if (servidor1Libre && servidor2Libre) return 2;
        if (servidor1Libre || servidor2Libre) return 1;
        return 0;
    }

    

    public Object[] getFilas(){
        return listaFilas.toArray();
    }

    public double totalGanancias(){
        return acumGanancias;
    }
}
